//定义小仓库的函数
import { defineStore } from 'pinia';
//登录成功:获取到用户唯一标识token,利用函数持久化存储|获取|删除token操作
//前台项目登录:花了很长时间讲解
import { getToken, removeToken, setToken } from '../utils/token-utils';
//ts定义对象的类型
import type { UserInfoState } from './interface';
//提示组件
import { ElMessage } from 'element-plus'
//项目路由数组:四个对象
import { staticRoutes, asyncRoutes, anyRoute } from '@/router/routes'
import type { RouteRecordRaw } from 'vue-router';
//引入登录请求函数
import { reqLogin, reqUserInfo, reqLogOut } from '@/api/acl';
// 引入路由器
import router from '@/router'
import { cloneDeep } from 'lodash'

// 参数一: 异步路由
// 参数二: 当前用户拥有的权限的name数组
const filterAsyncRoutes = (asyncRoutes: RouteRecordRaw[], routeNames: string[]) => {
  let result = asyncRoutes.filter(route => {
    // 同时筛选的时候需要筛选二级路由
    // route 当前的一级路由
    // route.children 是个数组,是包裹着所有的二级路由
    // route.children 把这个数组中的内容重新筛选一下,然后重新赋值给当前route.children
    if (route.children && route.children.length) {
      route.children = filterAsyncRoutes(route.children as RouteRecordRaw[], routeNames); // 递归筛选二级路由
    }
    return routeNames.includes(route.name as string);
  })
  return result
}

// 结论:
// filter 过滤的时候,得到的结果是一个新数组,这个新数组的地址和老数组的地址一定一样
// 但是数组中的成员如果是对象,那么新数组的成员对象和老数组的成员对象的地址一样

// 动态注册路由
const addRoutes = (allRoutes: RouteRecordRaw[]) => {
  allRoutes.forEach(route => {
    // router.addRoute() 方法是由 vue-router提供的,用来动态注册路由的,直接拿过来用即可
    router.addRoute(route);
  })
}



//pinia小仓库,选择器API,并非组合式API
export const useUserInfoStore = defineStore('userInfo', {
  //小仓库的数据
  state: (): UserInfoState => ({
    token: getToken() as string, //存储token 
    name: '',//存储用户名字
    avatar: '',//存储用户头像
    menuRoutes: [],//路由数组
    buttons:[],//将仓库存储每一个用户按钮权限的标记
  }),

  //小仓库的方法
  actions: {
    //点击登录按钮:调用仓库login方法,携带账号与密码
    async login(username: string, password: string) {
      //发登录请求:如果登录成功务必返回token
      //别忘记配置代理跨域
      let result: any = await reqLogin({ username, password });
      //登录成功,本地存储持久化存储token
      setToken(result.token); // 存到localStorage
      //本地仓库存储token
      this.token = result.token; // 存到store
    },

    //仓库的这个获取用户信息的方法,什么时候调用的?
    //守卫的时候调用次函数,获取用户信息
    //替换真实的获取用户信息接口:指定需要携带参数token
    async getInfo() {
      //获取用户需要请求头携带公共参数:token
      let result: any = await reqUserInfo();
      //仓库存储用户名字
      this.name = result.name;
      //仓库存储用户头像
      this.avatar = result.avatar;

      //存储用户信息中按钮权限的标记
      this.buttons = result.buttons;

      //小仓库把项目的路由进行存储
      // this.menuRoutes = staticRoutes // 改这行就OK了

      // 1. 侧边菜单栏的展示
      // staticRoutes, asyncRoutes, anyRoute
      // 对异步路由进行筛选
      // 功能:创建一个工具函数,对异步路由进行筛选
      // 参数:
      //  参数一: 异步路由,需要筛选的路由
      //  参数二: result.routes 用户信息返回的当前用户拥有的权限
      // 返回值:
      //  筛选之后,具有权限的路由
      const filterRoutes = filterAsyncRoutes(cloneDeep(asyncRoutes) , result.routes);
      
      const allRoutes = staticRoutes.concat(filterRoutes, anyRoute); // 所有的路由又合并成了一个

      this.menuRoutes = allRoutes;
      // 按理来说这里应该已经改变的侧边栏的展示,但是不好使,挖个坑一会填!!!
      // 侧边菜单栏的数据就是 this.menuRoutes

      // 2.动态路由注册
      addRoutes(allRoutes); // 筛选之后组装好的所有的路由,需要重新注册一次即可
    },
    //退出登录函数
    async reset() {
      await reqLogOut();
      // 删除local中保存的token
      removeToken()
      // 提交重置用户信息的mutation
      this.token = ''
      this.name = ''
      this.avatar = ''
    },
  },
});
